package httpserver

import (
	"context"
	"fmt"
	"net/http"

	"github.com/devops-smartbot/devops-smartbot/services/api-gateway/internal/clients"
	"github.com/devops-smartbot/devops-smartbot/services/api-gateway/internal/config"
	"github.com/devops-smartbot/devops-smartbot/services/api-gateway/internal/handlers"
	"github.com/devops-smartbot/devops-smartbot/services/api-gateway/internal/repository"
	"github.com/devops-smartbot/devops-smartbot/services/api-gateway/internal/server/http/router"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

// Server wraps the HTTP server and router.
type Server struct {
	cfg    config.Config
	http   *http.Server
}

// New constructs a new server with configured router.
func New(cfg config.Config) *Server {
	// Initialize gRPC clients
	ctx := context.Background()

	alertClient, err := clients.DialAlertService(ctx, cfg.AlertServiceAddr,
		grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		panic(fmt.Errorf("failed to dial alert service: %w", err))
	}

	ticketClient, err := clients.DialTicketService(ctx, cfg.TicketServiceAddr,
		grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		panic(fmt.Errorf("failed to dial ticket service: %w", err))
	}

	aiClient, err := clients.DialAIService(ctx, cfg.AIServiceAddr,
		grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		panic(fmt.Errorf("failed to dial ai service: %w", err))
	}

	// Initialize MongoDB for knowledge base
	mongoURI := "mongodb://admin:admin123@devops-mongodb:27017"
	mongoClient, err := mongo.Connect(ctx, options.Client().ApplyURI(mongoURI))
	if err != nil {
		panic(fmt.Errorf("failed to connect to MongoDB: %w", err))
	}
	mongoDB := mongoClient.Database("devops-smart-bot")

	// Initialize repositories
	knowledgeRepo := repository.NewMongoKnowledgeRepository(mongoDB)
	analysisRepo := repository.NewMongoAnalysisRepository(mongoDB)
	settingsRepo := repository.NewSettingsRepository(mongoDB)

	// Initialize handlers
	alertHandler := handlers.NewAlertHandler(alertClient)
	ticketHandler := handlers.NewTicketHandler(ticketClient)
	aiHandler := handlers.NewAIHandler(aiClient, alertClient, ticketClient, analysisRepo)
	authHandler := handlers.NewAuthHandler(cfg.JWTSecret)
	analyticsHandler := handlers.NewAnalyticsHandler(alertClient, ticketClient)
	knowledgeHandler := handlers.NewKnowledgeHandler(knowledgeRepo)
	settingsHandler := handlers.NewSettingsHandler(settingsRepo)

	// Initialize integration handler (with nil check for service availability)
	var integrationHandler *handlers.IntegrationHandler
	if cfg.IntegrationServiceAddr != "" {
		integrationHandler, _ = handlers.NewIntegrationHandler(cfg.IntegrationServiceAddr, nil)
	}

	// Create router with handlers
	r := router.New(alertHandler, ticketHandler, aiHandler, authHandler, analyticsHandler, knowledgeHandler, settingsHandler, integrationHandler, cfg.JWTSecret)

	return &Server{
		cfg: cfg,
		http: &http.Server{
			Addr:    fmt.Sprintf(":%d", cfg.HTTPPort),
			Handler: r,
		},
	}
}

// Start begins serving HTTP requests.
func (s *Server) Start() error {
	return s.http.ListenAndServe()
}

// Stop gracefully shuts down the server.
func (s *Server) Stop(ctx context.Context) error {
	return s.http.Shutdown(ctx)
}
